package com.zige.zige.view.panoplayer;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.GLES30;
import android.opengl.Matrix;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import com.zige.zige.R;
import com.zige.zige.view.panoplayer.glwrapper.GlCamera;
import com.zige.zige.view.panoplayer.glwrapper.GlGeometry;
import com.zige.zige.view.panoplayer.glwrapper.GlProgram;

/**
 * Created by admin on 16/1/5.
 */
public class PanoRenderer extends AbstractPanoRenderer implements SurfaceTexture.OnFrameAvailableListener {

    private static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
    private GlProgram mainProgram = null;
    private GlGeometry sphere = null;
    private Context context;
    private SurfaceTexture surfaceTexture = null;
    private int textureID = -1;
    private boolean shouldUpdateTexture = false;

    private float[] mvp = {
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f
    };

    public PanoRenderer(Context context) {
        this.context = context;
    }

    private String readTextFromFile(int resID) {
        InputStream is = context.getResources().openRawResource(resID);
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            reader.close();
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void setupPrograms() {
        String vertexShader = readTextFromFile(R.raw.vertex);
        String fragmentShader = readTextFromFile(R.raw.fragment);
        mainProgram = new GlProgram(vertexShader, fragmentShader);
        GLES30.glUseProgram(0);
    }

    private void setupVAOs() {
        sphere = GlGeometry.sphere();
    }

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        synchronized (this) {
            shouldUpdateTexture = true;
        }
    }

    @Override
    SurfaceTexture getSurfaceTexture() {
        return surfaceTexture;
    }

    @Override
    void onSurfaceCreated() {

        int[] textures = new int[1];
        GLES30.glGenTextures(1, textures, 0);
        textureID = textures[0];
        GLES30.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureID);
        GLES30.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
        GLES30.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
        surfaceTexture = new SurfaceTexture(textureID);
        surfaceTexture.setOnFrameAvailableListener(this);

        this.setupPrograms();
        this.setupVAOs();
        GLES30.glEnable(GLES30.GL_DEPTH_TEST);
    }

    @Override
    void onSurfaceChanged(int width, int height) {

    }

    @Override
    void prepareFrame() {
        synchronized (this) {
            if (shouldUpdateTexture) {
                shouldUpdateTexture = false;
                surfaceTexture.updateTexImage();
            }
        }
    }

    @Override
    void onDrawFrame(GlCamera camera) {
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);

        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
        GLES30.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureID);


        GLES30.glUseProgram(mainProgram.getProgram());
        Matrix.multiplyMM(mvp, 0, camera.getPerspectiveMatrix(), 0, camera.getViewMatrix(), 0);
        GLES30.glUniformMatrix4fv(mainProgram.getuMvp(), 1, false, mvp, 0);

        sphere.draw();

        GLES30.glBindVertexArray(0);
        GLES30.glUseProgram(0);
    }

    @Override
    void cleanUp() {
        surfaceTexture.release();
        mainProgram.cleanUp();
        sphere.free();
        int[] tmp = {textureID};
        GLES30.glDeleteTextures(1, tmp, 0);
    }
}
